#pragma once

#include "my_disk_vinfo.h"
#include "my_disk_buf.h"
#include "my_disk_context.h"
#include "my_disk_membufs.h"
#include "my_disk_hotspot.h"
#include "comm/my_syscall.h"
#include "event/my_event.h"
#include "comm/my_log.h"
#include "config/my_cache_config.h"
#include "event/my_event_loop.h"

typedef struct my_disk_volume_s my_disk_volume_t;
typedef void(*my_disk_data_reinsert_pt)(my_disk_volume_t *volume,
    my_cache_req_t *req, int64_t old_offset);

typedef struct my_disk_data_s my_disk_data_t;

struct my_disk_data_s {
    my_disk_vinfo_t         *vinfo;         // refer volume->voinfo
    my_disk_hotspot_t       *hotspot;       // refer volume->hotspot
    my_aio_manager_t        *aio_manager;   // refer volume->aio_manager
    my_disk_volume_t        *volume;        // refer volume
    my_disk_data_reinsert_pt reinsert_handler;

    my_disk_membufs_t       mem_bufs;
    my_disk_buf_t           *active;
    my_disk_buf_pool_t      buf_pool;

    my_mutex_t              write_mutex;

    my_spin_lock_t          alloc_cursor_lock;
    my_dispatch_event_t     *pending_alloc_cursor_event;

    my_spin_lock_t          alloc_buf_lock;
    my_dispatch_event_t     *pending_alloc_buf_event;

    my_spin_lock_t          flush_lock;
    my_queue_t              flush_pending_queue;
    my_bool_t               flushing;
    my_event_t              flush_event;
    my_disk_buf_t           *pending_flush_buf;
    my_aio_req_t            flush_aio_req;
    my_dispatch_event_t     dispatch_flush_event;

    my_spin_lock_t          recycle_lock;
    my_bool_t               recycleing;
    int64_t                 recycle_task;
    int64_t                 recycle_len;
    my_event_t              recycle_event;

    my_bool_t               open;
};

static inline void
my_disk_data_init(my_disk_data_t *disk_data) {
    bzero(disk_data, sizeof(my_disk_data_t));
    my_disk_buf_pool_init(&disk_data->buf_pool);
    my_disk_membufs_init(&disk_data->mem_bufs);
    my_mutex_init(&disk_data->write_mutex);
    my_spin_lock_init(&disk_data->alloc_cursor_lock);
    my_spin_lock_init(&disk_data->alloc_buf_lock);
    my_spin_lock_init(&disk_data->flush_lock);

    my_queue_init(&disk_data->flush_pending_queue);
}

my_bool_t
my_disk_data_open(my_disk_data_t *disk_data, my_disk_vinfo_t *vinfo,
    my_disk_hotspot_t *hotspot, my_aio_manager_t *aio_manager,
    my_disk_volume_t *volume, my_disk_data_reinsert_pt reinsert_handler);

void
my_disk_data_close(my_disk_data_t *disk_data);

void
my_disk_data_write(my_disk_data_t *disk_data, my_disk_write_context_t *context);

void
my_disk_data_read(my_disk_data_t *disk_data, my_disk_read_context_t *context);